#include "AD9910_Thread.hpp"
#include <stdlib.h>
#include <string>
#include "TCP_SERVER/TCP_SERVER.hpp"

#define HW_TIMER_DEV_NAME "timer14" /* 定时器名称 */

AD9910_Thread::AD9910_Thread(rt_uint32_t stack_size,
                             rt_uint8_t priority,
                             rt_uint32_t tick,
                             const char *name) : Thread(stack_size, priority, tick, name)
{
    m_ad9910_ram = new AD9910_RAM;
    m_tcp_server = TCP_SERVER::getInstance();

    hwTimerConfig();
}

AD9910_Thread::~AD9910_Thread()
{
    delete m_ad9910_ram;
    m_tcp_server = nullptr;
}

AD9910_Thread &AD9910_Thread::getInstance()
{
    static AD9910_Thread instance(2048, 9, 10, "AD9910_Thread");
    return instance;
}

void AD9910_Thread::run(void *parameter)
{
    m_profile = m_ad9910_ram->genRamProfile(10, 1023, 0, RAM_MODE::ContReCirc);

    m_ad9910_ram->writeProfile(m_profile);

    m_ad9910_ram->setProfileCtrlMode(0, 0, 0);

    m_ad9910_ram->writeRAM(m_ad9910_ram->SINC_WAVE);

    while (true)
    {
        const std::vector<uint8_t> *cmdData = m_tcp_server->getData();
        if (cmdData != nullptr)
        {
            processCmd(cmdData);
        }

        rt_thread_mdelay(10);
    }
}

rt_err_t AD9910_Thread::hwTimerConfig()
{
    rt_err_t ret = RT_EOK;
    rt_hwtimer_mode_t mode;     /* 定时器模式 */
    rt_uint32_t freq = 1000000; /* 计数频率 */

    /* 查找定时器设备 */
    hw_dev = rt_device_find(HW_TIMER_DEV_NAME);
    if (hw_dev == RT_NULL)
    {
        rt_kprintf("hwtimer run failed! can't find %s device!\n", HW_TIMER_DEV_NAME);
        return RT_ERROR;
    }

    /* 以读写方式打开设备 */
    ret = rt_device_open(hw_dev, RT_DEVICE_OFLAG_RDWR);
    if (ret != RT_EOK)
    {
        rt_kprintf("open %s device failed!\n", HW_TIMER_DEV_NAME);
        return ret;
    }

    /* 设置超时回调函数 */
    rt_device_set_rx_indicate(hw_dev, AD9910_Thread::hwTimerCallback);

    /* 设置计数频率(若未设置该项，默认为1Mhz 或 支持的最小计数频率) */
    rt_device_control(hw_dev, HWTIMER_CTRL_FREQ_SET, &freq);
    /* 设置模式为周期性定时器（若未设置，默认是HWTIMER_MODE_ONESHOT）*/
    mode = HWTIMER_MODE_PERIOD;
    ret = rt_device_control(hw_dev, HWTIMER_CTRL_MODE_SET, &mode);
    if (ret != RT_EOK)
    {
        rt_kprintf("set mode failed! ret is :%d\n", ret);
        return ret;
    }

    return ret;
}

rt_err_t AD9910_Thread::hwTimerstart(const rt_int32_t sec, const rt_int32_t usec)
{
    rt_hwtimerval_t timeout_s; /* 定时器超时值 */

    /* 设置定时器超时值并启动定时器 */
    timeout_s.sec = sec;   /* 秒 */
    timeout_s.usec = usec; /* 微秒 */
    if (rt_device_write(hw_dev, 0, &timeout_s, sizeof(timeout_s)) != sizeof(timeout_s))
    {
        rt_kprintf("set timeout value failed\n");
        return RT_ERROR;
    }
    return RT_EOK;
}

rt_err_t AD9910_Thread::hwTimerstop()
{
    return rt_device_control(hw_dev, HWTIMER_CTRL_STOP, RT_NULL);
}

rt_err_t AD9910_Thread::hwTimerCallback(rt_device_t dev, rt_size_t size)
{
    AD9910_RAM::IO_update();
    return RT_EOK;
}

void AD9910_Thread::processCmd(const std::vector<uint8_t> *cmdData)
{
    CMD_HEAD head = static_cast<CMD_HEAD>(cmdData->at(0));
    switch (head)
    {
    case CMD_HEAD::SetProfile:
        setProfile(cmdData);
        break;
    case CMD_HEAD::SetRamData:
        setRamData(cmdData);
        break;
    case CMD_HEAD::SetEnable:
        setEnable(cmdData);
        break;
    case CMD_HEAD::SetUpdate:
        setUpdate(cmdData);
        break;
    case CMD_HEAD::SetRamDemo:
        setRamDemo(cmdData);
        break;
    case CMD_HEAD::readRamData:
        readRamData(cmdData);
        break;
    case CMD_HEAD::SetTimer:
        setTimer(cmdData);
        break;
    default:
        break;
    }
}

void AD9910_Thread::setProfile(const std::vector<uint8_t> *cmdData)
{
    uint16_t addrRate = 1, endAddr = 1023, startAddr = 0;
    uint8_t ramMode = 0x04;
    const size_t dataSize = cmdData->size();
    if (dataSize >= 3)
    {
        addrRate = cmdData->at(1) << 8 | cmdData->at(2);
    }
    if (dataSize >= 5)
    {
        endAddr = cmdData->at(3) << 8 | cmdData->at(4);
    }
    if (dataSize >= 7)
    {
        startAddr = cmdData->at(5) << 8 | cmdData->at(6);
    }
    if (dataSize >= 8)
    {
        ramMode = cmdData->at(7);
    }
    m_profile = m_ad9910_ram->genRamProfile(addrRate,
                                            endAddr,
                                            startAddr,
                                            static_cast<RAM_MODE>(ramMode));
    m_ad9910_ram->writeProfile(m_profile);
}

void AD9910_Thread::setRamData(const std::vector<uint8_t> *cmdData)
{
    m_RAM_data.clear();
    size_t i = 0;
    while (m_RAM_data.size() < 1024)
    {
        uint32_t data;
        if (i < cmdData->size() - 2)
        {
            data = cmdData->at(i + 1) << 8 | cmdData->at(i + 2);
        }
        else
        {
            data = 0;
        }
        m_RAM_data.push_back(data > 16384 ? 16384 : data);
        i += 2;
    }

    m_ad9910_ram->writeRAM(m_RAM_data);
}

void AD9910_Thread::readRamData(const std::vector<uint8_t> *cmdData)
{
    const ram_data_t data = m_ad9910_ram->readRAM();
    for (size_t i = 0; i < data.size(); i++)
    {
        rt_kprintf("%d ", data[i]);
    }
    rt_kprintf("\n");
}

void AD9910_Thread::setEnable(const std::vector<uint8_t> *cmdData)
{
    uint8_t enable = 1;
    if (cmdData->size() >= 2)
    {
        enable = cmdData->at(1);
    }
    m_ad9910_ram->setRAM_Enable(enable);
}

void AD9910_Thread::setUpdate(const std::vector<uint8_t> *cmdData)
{
    m_ad9910_ram->IO_update();
}

void AD9910_Thread::setRamDemo(const std::vector<uint8_t> *cmdData)
{
    uint8_t index = 0;
    if (cmdData->size() >= 2)
    {
        index = cmdData->at(1);
    }
    switch (index)
    {
    case 0:
        m_ad9910_ram->writeRAM(m_ad9910_ram->SQUARE_WAVE);
        break;
    case 1:
        m_ad9910_ram->writeRAM(m_ad9910_ram->SINC_WAVE);
        break;
    case 2:
        m_ad9910_ram->writeRAM(m_ad9910_ram->TRIANGLE_WAVE);
        break;
    case 3:
        m_ad9910_ram->writeRAM(m_ad9910_ram->ALL_HIGH);
        break;
    case 4:
        m_ad9910_ram->writeRAM(m_ad9910_ram->ALL_LOW);
        break;
    default:
        m_ad9910_ram->writeRAM(m_ad9910_ram->SQUARE_WAVE);
        break;
    }
}

void AD9910_Thread::setTimer(const std::vector<uint8_t> *cmdData)
{
    bool timerEnable = false;
    if (cmdData->size() >= 2)
    {
        timerEnable = cmdData->at(1);
    }
    if (!timerEnable)
    {
        hwTimerstop();
        return;
    }
    rt_int32_t sec = 0, usec = 100;
    if (cmdData->size() >= 4)
    {
        sec = cmdData->at(2) << 8 | cmdData->at(3);
    }
    if (cmdData->size() >= 6)
    {
        usec = cmdData->at(4) << 8 | cmdData->at(5);
    }
    hwTimerstart(sec, usec);
}
